package namespace

import (
	"errors"
	"fmt"
	"reflect"

	"gddgame.cc/galaxy/binocle"
	"gddgame.cc/galaxy/binocle/module/report"
	. "gddgame.cc/galaxy/common/dsl/game"
	. "gddgame.cc/galaxy/common/dsl/game/ad"
	. "gddgame.cc/galaxy/common/dsl/game/attr"
	. "gddgame.cc/galaxy/common/dsl/game/badge"
	. "gddgame.cc/galaxy/common/dsl/game/item"
	. "gddgame.cc/galaxy/common/dsl/game/object"
	. "gddgame.cc/galaxy/common/dsl/game/skill"
	. "gddgame.cc/galaxy/common/dsl/game/user"
	"gddgame.cc/galaxy/core/sdk"
	"gddgame.cc/galaxy/project/star/star/controller"
	"gddgame.cc/galaxy/project/star/star/model"
	"gddgame.cc/galaxy/satellite/formula/nebula"
	"gddgame.cc/galaxy/server/composer"
	"gddgame.cc/galaxy/utils"
)

const (
	InfoSelf nebula.NSE = iota
	InfoUser
	InfoSkill
	InfoBuff
	InfoAttr
	InfoAttrGroup
	InfoObject
	InfoBadge
	InfoStore
	InfoShop
	InfoZone
	InfoMessage
	InfoRead
	InfoFriend
	InfoFriendInvited
	InfoSearch
	InfoBuy
	InfoSell
	InfoRepair
	InfoSwitchWeapon
	InfoSwitchMachine
	InfoSwitchItem
	InfoGift
	InfoRequestAd
	InfoResponseAd
	InfoReceiveReward
	InfoTask
	InfoTaskStatus
	InfoGameResult
)

/*
 游戏信息加载
*/
func InfoHandler(builder composer.Builder, client *sdk.AppClient, namespace nebula.Namespace) {
	var agent binocle.App
	builder.Factory("agent", &agent)

	namespace.SetCompress(false)

	reporter := agent.AddMetrics().Period(report.Minute1).Type(report.BothMetric).
		Aggregate(report.Sum, report.Max).Reporter()

	if err := namespace.Connect(func(socket *nebula.Socket, next nebula.Next) {
		var openId string
		err := socket.Get("open_id", &openId)
		if err != nil {
			_ = next(errors.New("Auth error"))
			return
		}
		_ = next(nil)
	}); err != nil {
		builder.Error(err)
	}

	controller.Env.BindNamespace(namespace)

	_ = namespace.On(InfoSelf, func(req *nebula.Request) {
		var openId string
		if err := req.Get("open_id", &openId); err != nil {
			return
		}
		_ = controller.Env.RefreshUserStatus(openId, false)
		language := GetLanguage(req)
		var user model.User
		detail, err := controller.Center.GetUserDetail(openId, &user, language)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		userDetail, err := controller.GetUserDetailInfo(req, &user, language)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		userDetail.BindGameUser(detail)
		req.SetCompress(true)
		req.Response(userDetail)
	})

	_ = namespace.On(InfoUser, func(req *nebula.Request, targetId string) {
		var openId string
		if err := req.Get("open_id", &openId); err != nil {
			return
		}
		var user model.User
		language := GetLanguage(req)
		info, err := controller.Center.GetUserInfo(openId, targetId, &user, language)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		userInfo, err := controller.GetUserPublicInfo(req, &user, language)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		userInfo.BindGameUser(info)
		req.SetCompress(true)
		req.Response(userInfo)
	})

	_ = namespace.On(InfoSkill, func(req *nebula.Request, updateTime int) {
		var items []*Skill
		var err error
		items, err = controller.Center.GetAllSkill(GetUpdateTime(req, updateTime))
		if err != nil {
			req.ResponseErr(err)
			return
		}
		req.SetCompress(true)
		req.Response(items)
	})

	_ = namespace.On(InfoBuff, func(req *nebula.Request, updateTime int) {
		var items []*Buff
		var err error
		items, err = controller.Center.GetAllBuff(GetUpdateTime(req, updateTime))
		if err != nil {
			req.ResponseErr(err)
			return
		}
		req.SetCompress(true)
		req.Response(items)
	})

	_ = namespace.On(InfoAttr, func(req *nebula.Request, updateTime int) {
		var items []*Attr
		var err error
		items, err = controller.Center.GetAllAttr(GetUpdateTime(req, updateTime))
		if err != nil {
			req.ResponseErr(err)
			return
		}
		req.SetCompress(true)
		req.Response(items)
	})

	_ = namespace.On(InfoAttrGroup, func(req *nebula.Request, updateTime int) {
		var items []*AttrGroup
		var err error
		items, err = controller.Center.GetAllAttrGroup(GetUpdateTime(req, updateTime))
		if err != nil {
			req.ResponseErr(err)
			return
		}
		req.SetCompress(true)
		req.Response(items)
	})

	_ = namespace.On(InfoObject, func(req *nebula.Request, updateTime int) {
		var items []*ObjectInfo
		var err error
		//language := GetLanguage(req)
		items, err = controller.Center.GetAllObject(GetUpdateTime(req, updateTime))
		if err != nil {
			req.ResponseErr(err)
			return
		}
		req.SetCompress(true)
		req.Response(items)
	})

	_ = namespace.On(InfoBadge, func(req *nebula.Request, updateTime int) {
		var items []*Badge
		var err error
		language := GetLanguage(req)
		items, err = controller.Center.GetAllBadge(GetUpdateTime(req, updateTime), language)
		//fmt.Println(items, err)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		req.SetCompress(true)
		req.Response(items)
	})

	_ = namespace.On(InfoStore, func(req *nebula.Request, updateTime int) {
		// 获取用户道具信息
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			return
		}
		var items []*model.UserItemExt
		var err error
		language := GetLanguage(req)
		items, err = controller.GetItems(req, userId, language, GetUpdateTime(req, updateTime))
		if err != nil {
			req.ResponseErr(err)
			return
		}
		req.SetCompress(true)
		req.Response(items)
	})
	_ = namespace.On(InfoShop, func(req *nebula.Request, updateTime int) {
		// 查看商店信息
		var items []*ShopItem
		var err error
		//language := GetLanguage(req)
		items, err = controller.Center.GetAllShopItems("", GetUpdateTime(req, updateTime))
		if err != nil {
			req.ResponseErr(err)
			return
		}
		req.SetCompress(true)
		req.Response(items)
	})
	_ = namespace.On(InfoZone, func(req *nebula.Request, updateTime int) {
		// 获取当前所有战区信息
		var zones []*model.ZoneNodeExt
		var err error
		language := GetLanguage(req)
		zones, err = controller.GetAllZoneNode(req, language, GetUpdateTime(req, updateTime))
		if err != nil {
			req.ResponseErr(err)
			return
		}
		req.SetCompress(true)
		req.Response(zones)
	})
	_ = namespace.On(InfoMessage, func(req *nebula.Request, updateTime int) {
		var openId string
		if err := req.Get("open_id", &openId); err != nil {
			return
		}
		_ = controller.Env.RefreshUserStatus(openId, false)
		// 获取当前消息
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			return
		}
		var um []UserMessage
		var err error
		um, err = controller.Center.GetMessages(userId, GetUpdateTime(req, updateTime))
		if err != nil {
			req.ResponseErr(err)
			return
		}
		language := GetLanguage(req)
		list := make([]*UserMessageExt, len(um))
		for key := range um {
			list[key] = NewUserMessage(&um[key], language, model.MessageTemplates)
		}
		req.SetCompress(true)
		req.Response(list)
	})
	_ = namespace.On(InfoRead, func(req *nebula.Request, id int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		if err := controller.Center.ReadMessage(userId, id); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		req.Response(true)
	})
	_ = namespace.On(InfoFriend, func(req *nebula.Request, updateTime int) {
		// 获取好友信息
		var openId string
		if err := req.Get("open_id", &openId); err != nil {
			return
		}
		t := GetUpdateTime(req, updateTime)
		language := GetLanguage(req)
		var userList []model.User
		var gameUserList []*model.GameOtherUser
		list, err := controller.Center.GetFriendList(openId, t, func(openIds []string) []UserBase {
			_ = controller.Center.FindUsers(openIds, "", nil, &userList)
			users := make([]UserBase, len(userList))
			gameUserList = make([]*model.GameOtherUser, len(userList))
			var err error
			for index, u := range userList {
				if gameUserList[index], err = controller.GetUserPublicInfo(req, &u, language); err != nil {
					fmt.Println(err)
				}
				users[index] = &u
			}
			return users
		}, language, true)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		for index, u := range gameUserList {
			u.BindGameUser(list[index])
		}
		req.SetCompress(true)
		req.Response(gameUserList)
	})
	_ = namespace.On(InfoFriendInvited, func(req *nebula.Request, updateTime int) {
		// 获取好友信息
		var openId string
		if err := req.Get("open_id", &openId); err != nil {
			return
		}
		t := GetUpdateTime(req, updateTime)
		language := GetLanguage(req)
		var userList []model.User
		var gameUserList []*model.GameOtherUser
		list, err := controller.Center.GetFriendList(openId, t, func(openIds []string) []UserBase {
			_ = controller.Center.FindUsers(openIds, "", nil, &userList)
			users := make([]UserBase, len(userList))
			gameUserList = make([]*model.GameOtherUser, len(userList))
			for index, u := range userList {
				gameUserList[index], _ = controller.GetUserPublicInfo(req, &u, language)
				users[index] = &u
			}
			return users
		}, language, false)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		for index, u := range gameUserList {
			u.BindGameUser(list[index])
		}
		req.SetCompress(true)
		req.Response(gameUserList)
	})
	_ = namespace.On(InfoSearch, func(req *nebula.Request, keyword string) { // 获取好友信息
		var openId string
		if err := req.Get("open_id", &openId); err != nil {
			return
		}
		language := GetLanguage(req)
		var userList []model.User
		var gameUserList []*model.GameOtherUser
		list, err := controller.Center.GetSearchList(openId, keyword, func(openIds []string) []UserBase {
			_ = controller.Center.FindUsers(openIds, keyword, nil, &userList)
			users := make([]UserBase, len(userList))
			gameUserList = make([]*model.GameOtherUser, len(userList))
			for index, u := range userList {
				gameUserList[index], _ = controller.GetUserPublicInfo(req, &u, language)
				users[index] = &u
			}
			return users
		}, language)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		for index, u := range gameUserList {
			u.BindGameUser(list[index])
		}
		req.SetCompress(true)
		req.Response(gameUserList)
	})
	_ = namespace.On(InfoBuy, func(req *nebula.Request, shopItem int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		var user model.User
		if err := controller.Center.GetUser(userId, &user); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		info := map[int]int{}
		if err := controller.BuyItem(req, "", shopItem, &user, info); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		if err := controller.AddItems(req, info, &user); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}

		req.Response(true)
	})
	_ = namespace.On(InfoSell, func(req *nebula.Request, userItemId int, number int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			req.ResponseErr(err)
			req.Response(false)
			return
		}
		var user model.User
		if err := controller.Center.GetUser(userId, &user); err != nil {
			req.ResponseErr(err)
			req.Response(false)
			return
		}
		// 道具是否有
		if err := controller.SellItem(req, userItemId, number, &user); err != nil {
			fmt.Println(err)
			req.SendError(err)
			req.Response(false)
			return
		}
		req.Response(true)
	})
	_ = namespace.On(InfoRepair, func(req *nebula.Request, userItemId int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			return
		}
		var user model.User
		if err := controller.Center.GetUser(userId, &user); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		// 道具是否有
		if err := controller.RepairItem(req, userItemId, &user); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}

		req.Response(true)
	})
	_ = namespace.On(InfoSwitchWeapon, func(req *nebula.Request, userItemId int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			return
		}
		var user model.User
		if err := controller.Center.GetUser(userId, &user); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		if err := controller.SwitchWeapon(req, &user, userItemId); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		req.Response(true)
	})
	_ = namespace.On(InfoSwitchMachine, func(req *nebula.Request, userItemId int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			return
		}
		var user model.User
		if err := controller.Center.GetUser(userId, &user); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		if err := controller.SwitchMachine(req, &user, userItemId); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		req.Response(true)
	})
	_ = namespace.On(InfoSwitchItem, func(req *nebula.Request, userItemId int, offset int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			return
		}
		var user model.User
		if err := controller.Center.GetUser(userId, &user); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		if err := controller.SwitchItem(req, &user, userItemId, offset); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		req.Response(true)
	})
	_ = namespace.On(InfoGift, func(req *nebula.Request, gift string, number int) {
		// 执行抽奖
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			req.ResponseErr(err)
			return
		}
		var user model.User
		if err := controller.Center.GetUser(userId, &user); err != nil {
			req.ResponseErr(err)
			return
		}
		language := GetLanguage(req)
		// 判断用户是否有该gift
		result, err := controller.GetGift(req, &user, gift, number, language)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		req.Response(result)
	})
	_ = namespace.On(InfoRequestAd, func(req *nebula.Request, plane int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			req.ResponseErr(err)
			return
		}
		var user model.User
		if err := controller.Center.GetUser(userId, &user); err != nil {
			req.ResponseErr(err)
			return
		}
		t, err := NextAdTime(controller.Env, user.OpenId, AdPlane(plane))
		if err != nil {
			req.ResponseErr(err)
			return
		}
		// 返回剩余时长：秒
		//t.Next = t.Next - time.Now().Unix()
		//if t.Next < 0 {
		//	t.Next = 0
		//}
		reporter.Increase("ad.plane.request." + string(t.Plane))
		reporter.Increase("ad.brand.request." + t.Brand)
		//fmt.Println(t)
		req.Response(t)
	})
	_ = namespace.On(InfoResponseAd, func(req *nebula.Request, plane int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		var user model.User
		if err := controller.Center.GetUser(userId, &user); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		t, err := NextAdTime(controller.Env, user.OpenId, AdPlane(plane))
		if err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		if !t.Verify() {
			req.Response(false)
			return
		}
		if err := ResponseAdTime(controller.Env, user.OpenId, t); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		reporter.Increase("ad.plane.response." + string(t.Plane))
		reporter.Increase("ad.brand.response." + t.Brand)
		if err := controller.Center.UpdateStatSingle(req, &user, controller.Center.StatData, model.AdStat, 1, false); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		data := make(map[string]interface{})
		if err := controller.UpdateBadgeSingle(req, &user, model.AdBadge, data); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		if err := controller.Center.UpdateUser(&user, data); err != nil {
			req.SendError(err)
			req.Response(false)
			return
		}
		req.Response(true)
	})
	_ = namespace.On(InfoReceiveReward, func(req *nebula.Request, messageId int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			return
		}
		var user model.User
		if err := controller.Center.GetUser(userId, &user); err != nil {
			req.ResponseErr(err)
			return
		}
		language := GetLanguage(req)
		reward, err := controller.ReceiveRewardMessage(req, &user, messageId, controller.Center.GetItem(), language)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		req.Response(reward)
	})
	_ = namespace.On(InfoTask, func(req *nebula.Request, ids []int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			req.ResponseErr(err)
			return
		}
		language := GetLanguage(req)
		result, err := controller.Center.GetTaskFromIds(ids, language)
		if err != nil {
			req.SendError(err)
			return
		}
		req.Response(result)
	})
	_ = namespace.On(InfoTaskStatus, func(req *nebula.Request, ids []int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			req.ResponseErr(err)
			return
		}
		if len(ids) == 0 {
			// 获取所有战区任务id
			tmpIds, err := controller.GetAllZoneTaskIds(req)
			if err != nil {
				req.ResponseErr(err)
				return
			}
			ids = tmpIds
		}
		processMap, err := controller.Center.GetTaskProcess(userId, ids)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		result := make(map[string]int, len(ids))
		for _, id := range ids {
			value := 0
			if process, ok := processMap[id]; ok {
				for _, v := range process {
					value += int(v)
				}
			}
			result[utils.ToString(id)] = value
		}
		req.Response(result)
	})
	_ = namespace.On(InfoGameResult, func(req *nebula.Request, userGameId int) {
		var userId int
		if err := req.Get("user_id", &userId); err != nil {
			return
		}
		language := GetLanguage(req)
		result, err := controller.Center.GetUserGame(userId, userGameId)
		if err != nil {
			req.ResponseErr(err)
			return
		}
		Result := utils.ToType(result, reflect.TypeOf(&model.GameResult{})).(*model.GameResult)
		Result.Reward.BindInfo(controller.Center.GetItem(), language)
		req.Response(Result)
	})
}
